/* * Copyright (C) 2015 Can Elmas * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.canelmas.let; import android.content.pm.PackageManager; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; import android.text.TextUtils; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.reflect.MethodSignature; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; /** * Created by can on 07/10/15. */ public final class RuntimePermissionRequest { private static final AtomicInteger PERMISSIONS_REQUEST_CODE = new AtomicInteger(); final Object source; final ProceedingJoinPoint joinPoint; public RuntimePermissionRequest(ProceedingJoinPoint joinPoint, Object source) { this.source = source; this.joinPoint = joinPoint; } public void retry() { proceed(true); } protected Object proceed() { return proceed(false); } private Object proceed(final boolean retry) { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); final String[] permissionList = method.getAnnotation(AskPermission.class).value(); Logger.log(">>> " + signature.getName() + "() requires " + permissionList.length + " permission"); // Permissions to ask and to show rationales final List<String> permissionsToAsk = new ArrayList<>(); final List<String> permissionsToExplain = new ArrayList<>(); final LetContext letContext = new LetContext(source); for (String permission : permissionList) { Logger.log("\t" + permission); if (!isPermissionValid(permission)) { throw new LetException("Permission name not valid!"); } else { final int permissionResult = ContextCompat.checkSelfPermission(letContext.getActivity(), permission); Logger.log("\t\talreadyGranted=" + String.valueOf(permissionResult != -1)); if (permissionResult != PackageManager.PERMISSION_GRANTED) { final boolean showRationale = ActivityCompat.shouldShowRequestPermissionRationale(letContext.getActivity(), permission); Logger.log("\t\tshowRationale=" + showRationale); if (showRationale && !retry) { permissionsToExplain.add(permission); } else { permissionsToAsk.add(permission); } } } } /** * -Show rationales if necessary and return, before making any permission request * -Trigger necessary permission request and return * -Permissions needed already granted, no need to make request; proceed with the actual method */ RuntimePermissionListener listener = RuntimePermissionListener.class.isInstance(source) ? (RuntimePermissionListener) source : null; if (!permissionsToExplain.isEmpty()) { Logger.log("<<< Should show Rationale"); if (null != listener) { listener.onShowPermissionRationale(permissionsToExplain, new RuntimePermissionRequest(joinPoint, source)); } else { throw new LetException(source + " or its parent should implement RuntimePermissionListener"); } return null; } else if (!permissionsToAsk.isEmpty()) { Logger.log("<<< Making permission request"); final int requestCode = PERMISSIONS_REQUEST_CODE.getAndIncrement() & 0xff; DelayedTasks.add(new DelayedTasks.Task(permissionsToAsk, requestCode, joinPoint)); letContext.requestPermissions(permissionsToAsk.toArray(new String[]{}), requestCode); return null; } else { Logger.log("<<< Permissions granted"); try { return joinPoint.proceed(); } catch (Throwable t) { throw new LetException("Proceeding with the annotated method failed!", t); } } } private boolean isPermissionValid(final String permissionName) { // TODO return !TextUtils.isEmpty(permissionName); } }